/*
 * Copyright (c) 2011 Ball State University
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * NOTE:
 * Derivative work based on the Google IO 2011 Schedule app released for open source
 * http://code.google.com/p/iosched/
 */

package edu.bsu.android.gtv.apps.bconnected.ui;

import java.util.ArrayList;

import edu.bsu.android.gtv.apps.bconnected.R;
import edu.bsu.android.gtv.apps.bconnected.data.CourseData;
import edu.bsu.android.gtv.apps.bconnected.data.PersonData;
import edu.bsu.android.gtv.apps.bconnected.objects.Course;
import edu.bsu.android.gtv.apps.bconnected.objects.Person;
import edu.bsu.android.gtv.apps.bconnected.ui.HomeActivity;
import edu.bsu.android.gtv.apps.bconnected.ui.base.BaseActivity;
import edu.bsu.android.gtv.apps.bconnected.util.AnalyticsUtils;
import edu.bsu.android.gtv.apps.bconnected.util.Constants;
import edu.bsu.android.gtv.apps.bconnected.util.LoginHelper;
import edu.bsu.android.gtv.apps.bconnected.util.UIUtils;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.LinearLayout;
import android.widget.TabHost;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

/**
 * An activity that shows detail information for a course including description, classmates and instructors. Activity that is started when a 
 * user selects a course from the list on the {@link CourseFragment}.
 * @author Kyle Parker, University Computing Services
 */
public class CourseInfoActivity extends BaseActivity {
    private static final String TAG = "CourseInfoActivity";
    private static final String TAG_DESCRIPTION = "desc";
    private static final String TAG_CLASSMATES = "classmates";
    private static final String TAG_INSTRUCTORS = "instructors";

    private TabHost mTabHost;
    private View mLoadingSpinner;
    private View mClassmateSpinner;
    private View mInstructorSpinner;
    private Activity mActivity;
    private Course mCourse;
    private BroadcastReceiver mReceiver;

    private String mLoginGuid;
    private String mBSUID;
    private String mBuildingDesc;
    private String mLatitude;
    private String mLongitude;
    private String mCourseRefNum = "";
    private boolean mLogin;
    
    private int mCoursePosition = 0; 
    private int mTermPosition = 0;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_course_info);
		
        getActivityHelper().setupActionBar(false, "Course Schedule | Course Info");        
        mActivity = this;
        
        handleLogout();    
        handleLogin();
                
        mTabHost = (TabHost) findViewById(android.R.id.tabhost);
       	mTabHost.setup();

        mLoadingSpinner = findViewById(R.id.loading_spinner); 
        mLoadingSpinner.setVisibility(View.VISIBLE);	
        
        mClassmateSpinner = findViewById(R.id.spinner_classmate); 
        mClassmateSpinner.setVisibility(View.VISIBLE);		
        
        mInstructorSpinner = findViewById(R.id.spinner_instructor); 
        mInstructorSpinner.setVisibility(View.VISIBLE);

        setupDescriptionTab();
        setupClassmatesTab();
        setupInstructorsTab();

        getExtras();
		
		// Hide the event information while the data is loading
		hideCourseInfo();
		if (mLogin) {
			loadCourseInfo();
		}

        AnalyticsUtils.getInstance(mActivity).trackPageView("/CourseInfo");
    }
    
    @Override 
    public void onDestroy() {
    	super.onResume();
    	mActivity.unregisterReceiver(mReceiver);
    }
    
    /**
     * Get the extras from the Intent
     */
    public void getExtras() {
		Bundle extras = getIntent().getExtras(); 
 
		if (extras != null) {
			if (extras.getString(Constants.EXTRA_COURSE_REF_NUM) != null) {
				mCourseRefNum = extras.getString(Constants.EXTRA_COURSE_REF_NUM);
			}
			if (extras.getString(Constants.EXTRA_TERM_POSITION) != null) {
				mTermPosition = Integer.parseInt(extras.getString(Constants.EXTRA_TERM_POSITION));
			}
		}
    }

    /**
     * Using a new thread, separate from the main activity, load the course information from the service handler
     */
    public void loadCourseInfo() {	
        Runnable load = new Runnable(){
            public void run() {
            	try {
            		if (CourseData.getCourseCount() > 0) {
		            	// If a CRN was returned from the classmate activity, retrieve the position in the object for that course
		    	        if (mCourseRefNum.length() > 0) {
		    	        	mCoursePosition = CourseData.getCourseByCRN(mCourseRefNum);
		    	        } 

		                mCourse = CourseData.getCourse(mCoursePosition);
            		}
            		
        	    	mActivity.runOnUiThread(returnCourse);
            	} catch (Exception ex) {
                    AnalyticsUtils.getInstance(mActivity).trackPageView(TAG + ": " + ex.getMessage());
            	}    	    	
            }
        };
        
        Thread thread = new Thread(null, load, "loadCourseInfo");
        thread.start();
    }
    
    /**
     * Load the course info from the service handler and set the visibility of the spinner to "gone"
     */
    private Runnable returnCourse = new Runnable(){
        public void run() {
            displayCourseInfo();
            mLoadingSpinner.setVisibility(View.GONE);
        }
    };

    /*
     * Using a new thread, separate from the main activity, load the classmates from the service handler
     */
    private void loadClassmate() {		
        Runnable load = new Runnable(){
            public void run() {
            	try {
	    	    	PersonData.initializeClassmate(mBSUID, mCourse.getCourseRefNum(), mCourse.getTermNumber(), mCourse.getTermYear(), 
	    	    			mLoginGuid, mActivity); 
	    	    	
	    	    	mActivity.runOnUiThread(returnClassmate);  
            	} catch (Exception ex) {
                    AnalyticsUtils.getInstance(mActivity).trackPageView(TAG + ": " + ex.getMessage());
            	}
            }
        };
        
        Thread thread = new Thread(null, load, "loadCourseInfo");
        thread.start();
    }
    
    /**
     * Load the classmates from the service handler
     */
    private Runnable returnClassmate = new Runnable(){
        public void run() {
        	// If the call to the classmate service did not return the "error" attribute, then display the classmates, otherwise 
        	// the expiration date has expired for the user or they are not authorized under the current credentials to access the information.
        	// When retrieving data from the .NET service handler, the BSU ID and login guid are matched against the SQL Server database.  If
        	// the combination of the two do not match, then the user is not permitted to retrieve the requested data.  The guards against
        	// someone hacking the querystring parameters to retrieve the information of another student.
        	if (PersonData.getClassmateAuth()) {
            	displayClassmates();
                
                if (PersonData.getClassmateCount() == 0) {
                    TextView empty = ((TextView) findViewById(R.id.empty_classmates));
                    empty.setVisibility(View.VISIBLE);
                }
        	} else {
                findViewById(R.id.course_info_container).setVisibility(View.VISIBLE);
                TextView empty = ((TextView) findViewById(R.id.empty_classmates));
                empty.setVisibility(View.VISIBLE);
                empty.setText(R.string.error_auth);
        	}

            mClassmateSpinner.setVisibility(View.GONE);
        }
    };

    /**
     * Using a new thread, separate from the main activity, load the instructors from the service handler
     */
    private void loadInstructor() {		
        Runnable load = new Runnable(){
            public void run() {
            	try {
    	        	PersonData.initializeInstructor(mCourse.getCourseRefNum(), mCourse.getTermNumber(), mCourse.getTermYear(), mActivity);   
        	    	
        	    	mActivity.runOnUiThread(returnInstructor); 	    
            	} catch (Exception ex) {
                    AnalyticsUtils.getInstance(mActivity).trackPageView(TAG + ": " + ex.getMessage());
            	}
            }
        };
        
        Thread thread = new Thread(null, load, "loadInstructor");
        thread.start();
    }
    
    /**
     * Load the instructor info from the service handler
     */
    private Runnable returnInstructor = new Runnable(){
        public void run() {
        	displayInstructors();
            mInstructorSpinner.setVisibility(View.GONE);
            
            if (PersonData.getInstructorCount() == 0) {
                TextView empty = ((TextView) findViewById(R.id.empty_instructors));
                empty.setVisibility(View.VISIBLE);
            }
        }
    };
    
    /**
     * Display the course information, including the classmates and instructors
     */
    private void displayCourseInfo() {
       	if (mCourse != null) {
	    	// Display the course information including campus map clickable image (launch map intent), classmates and instructors
        	displayCourseDesc();
        	loadClassmate();
        	loadInstructor();
    	} else { 
    		hideCourseInfo();
    	}
    }
    
    /**
     * Display the course title, section, day/time and description
     */
    private void displayCourseDesc() {
    	LinearLayout view = (LinearLayout) findViewById(R.id.course_info_container);
        view.setVisibility(View.VISIBLE);
    	view.setBackgroundResource(R.color.content_background);
		
    	// Set the values for the map intent
		mBuildingDesc = mCourse.getBuildingDesc();
		mLongitude = mCourse.getLongitude();
		mLatitude = mCourse.getLatitude();        
    	
		UIUtils.displayTextView(view, R.id.course_full_title, mCourse.getFullTitle());
		UIUtils.displayTextView(view, R.id.course_title, mCourse.getCourseWithTitle());
		UIUtils.displayTextView(view, R.id.section, "Section " + mCourse.getSection());
		UIUtils.displayTextView(view, R.id.day_time, mCourse.getDayTime());
		UIUtils.displayTextView(view, R.id.location, mCourse.getLocation());
		UIUtils.displayTextView(view, R.id.course_desc, mCourse.getCourseDesc());
              
    	// Display the standard map graphic and launch the Google Maps intent when tapped
    	ImageView image = (ImageView) view.findViewById(R.id.campus_map);
    	
    	image.setImageResource(R.drawable.campus_map);
    	image.setOnClickListener(new OnClickListener(){
			public void onClick(View v) {
            	Intent intent = UIUtils.getGoogleMapsIntent(mBuildingDesc, mLatitude, mLongitude);
            	
            	if (intent != null) {
            		startActivity(intent);
            	} else {
                    final String errorText = mActivity.getString(R.string.toast_error_location); 
                    Toast.makeText(mActivity, errorText, Toast.LENGTH_LONG).show();
            	}
			}
		});
    }

    /**
     * Hide the course view during the load process or if the course object is empty
     */
    private void hideCourseInfo() {  
    	LinearLayout view = (LinearLayout) findViewById(R.id.course_info_container);
        view.setVisibility(View.GONE);			
        view.setBackgroundResource(R.drawable.empty_course_background);
    }
    
    /**
     * Display the classmates for the course
     */
    private void displayClassmates() { 
    	if (PersonData.getClassmateCount() > 0) {
            TextView note = ((TextView) findViewById(R.id.note_classmate));
            note.setVisibility(View.VISIBLE);
            
            ClassmateAdapter adapter = new ClassmateAdapter(mActivity, PersonData.getClassmates());
            
            ListView lv = ((ListView) findViewById(R.id.classmates));
            lv.setAdapter(adapter); 
            lv.setOnItemClickListener(new OnItemClickListener(){
    			public void onItemClick(AdapterView<?> parentView, View childView, int position, long id) {
    		        final Intent intent = new Intent(Intent.ACTION_VIEW, null, mActivity, ClassmateActivity.class);
    				
    		        intent.putExtra(Constants.EXTRA_CLASSMATE_POSITION, Integer.toString(position));
    		        intent.putExtra(Constants.EXTRA_COURSE_POSITION, Integer.toString(mCoursePosition));
    		        intent.putExtra(Constants.EXTRA_TERM_POSITION, Integer.toString(mTermPosition));

    		        UIUtils.setLastID(mActivity, Constants.PREF_COURSE_TAB, 1); 

    		        mActivity.startActivity(intent);
    			}
    		});
    	}
    }
    
    /**
     * Display the instructors for the course
     */
    private void displayInstructors() { 
    	if (PersonData.getInstructorCount() > 0) {
            InstructorAdapter adapter = new InstructorAdapter(mActivity, PersonData.getInstructors());
            
            ListView lv = ((ListView) findViewById(R.id.instructors)); 
            lv.setAdapter(adapter);
            lv.setOnItemClickListener(new OnItemClickListener(){
    			public void onItemClick(AdapterView<?> parentView, View childView, int position, long id) {
    		        final Intent intent = new Intent(Intent.ACTION_VIEW, null, mActivity, InstructorActivity.class);
    		        
    		        intent.putExtra(Constants.EXTRA_INSTRUCTOR_POSITION, Integer.toString(position));
    		        intent.putExtra(Constants.EXTRA_COURSE_POSITION, Integer.toString(mCoursePosition));
    		        intent.putExtra(Constants.EXTRA_TERM_POSITION, Integer.toString(mTermPosition));

    		        UIUtils.setLastID(mActivity, Constants.PREF_COURSE_TAB, 2); 

    		        mActivity.startActivity(intent);
    			}
    		});
    	}		 
    }

    /**
     * ClassmateAdapter used to populate the listview for the classmates
     */
    private class ClassmateAdapter extends ArrayAdapter<Person> {
        private ArrayList<Person> items;
        
        public ClassmateAdapter(Context context, ArrayList<Person> items) {
            super(context, 0, items);
            this.items = items;
        }
        
        @Override
        public View getView(int position, View convertView, ViewGroup parent)  {                   	
            View view = convertView;
            
            if (view == null) {
            	view = LayoutInflater.from(mActivity).inflate(R.layout.list_item_tab, null);
            } 
            
            // Retrieve the classmate information and set the TextView items for the list
            Person classmate = items.get(position);  
             
            if (classmate != null) {
            	UIUtils.displayTextView(view, R.id.item, (classmate.getLastName() + ", " + classmate.getFirstName() + " " + classmate.getNameSuffix()).trim() + 
        				" (" + classmate.getCourseCount() + ")");
            }
             
            return view;
        }
    }

    /**
     * InstructorAdapter used to populate the listview for the instructors
     * This view is more than the standard Android ListView - this uses a layout and displays multiple rows of text.
     */
    private class InstructorAdapter extends ArrayAdapter<Person>  {
        private ArrayList<Person> items;

        public InstructorAdapter(Context context, ArrayList<Person> items) {
            super(context, 0, items);
            this.items = items;
        }
        
        @Override
        public View getView(int position, View convertView, ViewGroup parent)  {                    	
            View view = convertView;
            
            if (view == null) {
            	view = LayoutInflater.from(mActivity).inflate(R.layout.list_item_instructor, null);
            } 
            
            // Retrieve the instructor information and set the TextView items for the list
            Person instructors = items.get(position);            
            if (instructors != null) {
            	UIUtils.displayTextView(view, R.id.name, (instructors.getNamePrefix() + " " + instructors.getFirstName() + 
            			" " + instructors.getLastName() + " " + instructors.getNameSuffix()).trim());
            	UIUtils.displayTextView(view, R.id.title, instructors.getTitleRank());
            	UIUtils.displayTextView(view, R.id.department, instructors.getDepartment());
            }
            
            return view;
        }
    }

    /**
     * Build and add "description" tab.
     */
    private void setupDescriptionTab() {
        mTabHost.addTab(mTabHost.newTabSpec(TAG_DESCRIPTION)
                .setIndicator(UIUtils.buildIndicator(R.string.tab_description, mActivity))
                .setContent(R.id.tab_course_desc));
    }
    
    /**
     * Build and add "classmates" tab.
     */
    private void setupClassmatesTab() {
        mTabHost.addTab(mTabHost.newTabSpec(TAG_CLASSMATES)
                .setIndicator(UIUtils.buildIndicator(R.string.tab_course_classmates, mActivity))
                .setContent(R.id.tab_classmate));
    }
    
    /**
     * Build and add "instructors" tab.
     */
    private void setupInstructorsTab() {
        mTabHost.addTab(mTabHost.newTabSpec(TAG_INSTRUCTORS)
                .setIndicator(UIUtils.buildIndicator(R.string.tab_course_instructors, mActivity))
                .setContent(R.id.tab_instructor));
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    	MenuInflater inflater = new MenuInflater(this);
    	inflater.inflate(R.menu.map_menu_items, menu);
    	
    	super.onCreateOptionsMenu(menu);
        
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_map:
            	Intent intent = UIUtils.getGoogleMapsIntent(mBuildingDesc, mLatitude, mLongitude);
            	
            	if (intent != null) {
            		startActivity(intent);
            	} else {
                    final String errorText = mActivity.getString(R.string.toast_error_location); 
                    Toast.makeText(mActivity, errorText, Toast.LENGTH_LONG).show();
            	}
                return true;
        }
        
        return super.onOptionsItemSelected(item);
    }

    /** 
     * In order to protect the activity from the back stack after a student logs out, remove the activity 
     * If the student hits the back button, this will take them to the Home activity
     */
    private void handleLogout() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Constants.ACTION_LOGOUT);
        mReceiver = new BroadcastReceiver() {
			@Override
			public void onReceive(Context context, Intent intent) {
		        intent = new Intent(Intent.ACTION_VIEW, null, mActivity, HomeActivity.class);
		        intent.putExtra(Constants.EXTRA_LOGIN_STATUS, Integer.toString(Constants.LOGIN_STATUS_LOGOUT));
		        
		        mActivity.startActivity(intent); 
			    mActivity.finish();
			}
		};
		
        mActivity.registerReceiver(mReceiver, intentFilter);
    }
    
    /**
     * Determine if the person has logged in and whether there is a person object in the database
     * Get the student's BSU ID for use throughout the application
     */
    private void handleLogin() {
    	Person person = LoginHelper.checkLogin(mActivity);
    	
    	if (person != null) {
    		mBSUID = person.getBSUID();
        	mLoginGuid = person.getLoginGuid();
        	
        	mLogin = true;
    	} else {
	        Intent intent = new Intent(Intent.ACTION_VIEW, null, mActivity, HomeActivity.class);
	        intent.putExtra(Constants.EXTRA_LOGIN_STATUS, Integer.toString(Constants.LOGIN_STATUS_NOT_LOGGED_IN));
	        
	        mActivity.startActivity(intent); 
		    mActivity.finish();
		    
		    mLogin = false;
    	}    	
    }
}
